﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Diagnostics;
using Devtm.ServiceModel.Proxy.Events;
using System.Reflection;


namespace Devtm.ServiceModel.Proxy
{


    /// <summary>
    /// Base for client.
    /// contains all no generic members
    /// </summary>
    public abstract class ClientBase //: IDisposable
    {

        protected static object staticLock = new object();   

        #region Ctor

        public ClientBase()
        {         
            
        }        

        #endregion


        #region Intercept

        public InterceptBeforeEventArgs CatchBefore(Object service, params object[] parameters)
        {

            StackFrame s = new StackTrace().GetFrame(1);
            MethodInfo m = s.GetMethod() as MethodInfo;

            InterceptBeforeEventArgs args = new InterceptBeforeEventArgs(m, parameters)
            {
                Proxy = this,
                Service = service,
            };

            var Properties = Configuration.GetEventHandlerOperation(m);

            if (Properties.HasInterceptBeforeSubscription)
                Properties.EventInterceptBeforeAction(args);

            return args;

        }


        public void CatchException(Exception inner, Object service, params object[] parameters)
        {

            StackFrame s = new StackTrace().GetFrame(1);
            MethodInfo m = s.GetMethod() as MethodInfo;

            Configuration.Factory.Log(inner, s.GetMethod(), parameters);

            var Properties = Configuration.GetEventHandlerOperation(m);

            ExceptionEventArgs args = new ExceptionEventArgs(s.GetMethod(), parameters)
            {
                InnerException = inner,
                Proxy = this,
                Service = service
            };

            if (Properties.HasExceptionSubscription)
                Properties.EventException(args);

        }


        public void CatchAfterVoid(Object service, params object[] parameters)
        {

            StackFrame s = new StackTrace().GetFrame(1);
            MethodInfo m = s.GetMethod() as MethodInfo;

            var Properties = Configuration.GetEventHandlerOperation(m);

            InterceptAfterEventArgs args = new InterceptAfterEventArgs(s.GetMethod(), parameters)
            {
                Proxy = this,
                Service = service,
                Value = null
            };

            if (Properties.HasInterceptAfterSubscription)
                Properties.EventInterceptAfterAction(args);
        
        }


        public void CatchAfter<T>(Object service, T value, params object[] parameters)
        {

            StackFrame s = new StackTrace().GetFrame(1);
            MethodInfo m = s.GetMethod() as MethodInfo;

            var Properties = Configuration.GetEventHandlerOperation(m);

            InterceptAfterEventArgs args = new InterceptAfterEventArgs(s.GetMethod(), parameters)
            {
                Proxy = this,
                Service = service,
                Value = value
            };

            if (Properties.HasInterceptAfterSubscription)
                Properties.EventInterceptAfterAction(args);
        
        }
        
        #endregion


        protected void Client_Faulted(object sender, EventArgs e)
        {
            FinalizeInvoker(sender as ICommunicationObject);
        }


        /// <summary>
        /// Finalizes the Communication Object
        /// </summary>
        /// <param name="_communicationObject">The _communication object.</param>
        public void FinalizeInvoker(ICommunicationObject _communicationObject)
        {
            if (_communicationObject != null)
            {
                try
                {
                    _communicationObject.Close();
                }
                catch
                {
                    _communicationObject.Abort();
                }
            }
        }

        internal ProxyConfiguration Configuration { get; set; }



        public void Log(string message, string @interface, string operationName, params object[] parameters)
        {
            Configuration.Factory.Log(message, @interface, operationName, parameters);
        }

        //public void Dispose()
        //{
        //    throw new NotImplementedException();
        //}

        //public void Dispose(bool disposing)
        //{
        //    if (disposing)
        //    {

        //    }
        //}

    }

}
